home *** CD-ROM | disk | FTP | other *** search
/ MacAddict 104 / MacAddict_104_2005-04.iso / Software / Internet & Communication / WordPress 1.2.2 freeware.dmg / wordpress / wp-includes / class-xmlrpc.php < prev    next >
Encoding:
PHP Script  |  2004-05-22  |  30.2 KB  |  1,179 lines

  1. <?php                    // -*-c++-*-
  2. // by Edd Dumbill (C) 1999-2001
  3. // <edd@usefulinc.com>
  4. // $Id: class-xmlrpc.php,v 1.7 2004/05/21 21:29:57 michelvaldrighi Exp $
  5.  
  6.  
  7. # additional fixes for case of missing xml extension file by Michel Valdrighi <m@tidakada.com>
  8.  
  9.  
  10. // Copyright (c) 1999,2000,2001 Edd Dumbill.
  11. // All rights reserved.
  12. //
  13. // Redistribution and use in source and binary forms, with or without
  14. // modification, are permitted provided that the following conditions
  15. // are met:
  16. //
  17. //    * Redistributions of source code must retain the above copyright
  18. //      notice, this list of conditions and the following disclaimer.
  19. //
  20. //    * Redistributions in binary form must reproduce the above
  21. //      copyright notice, this list of conditions and the following
  22. //      disclaimer in the documentation and/or other materials provided
  23. //      with the distribution.
  24. //
  25. //    * Neither the name of the "XML-RPC for PHP" nor the names of its
  26. //      contributors may be used to endorse or promote products derived
  27. //      from this software without specific prior written permission.
  28. //
  29. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  30. // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  31. // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  32. // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  33. // REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  34. // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  35. // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  36. // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  37. // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  38. // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  39. // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  40. // OF THE POSSIBILITY OF SUCH DAMAGE.
  41.  
  42.  
  43. # b2 fix. some servers have stupid warnings
  44. #error_reporting(0);
  45.  
  46. if (!function_exists('logIO')) {
  47.     function logIO($m="",$n="") {
  48.     return(true);
  49.     }
  50. }
  51.  
  52.  
  53. if (!function_exists('xml_parser_create')) {
  54. // Win 32 fix. From: "Leo West" <lwest@imaginet.fr>
  55. // Fix for missing extension file. From: "Michel Valdrighi" <m@tidakada.com>
  56.     if($WINDIR) {
  57.         if (@dl("php3_xml.dll")) {
  58.             define("CANUSEXMLRPC", 1);
  59.         } else {
  60.             define("CANUSEXMLRPC", 0);
  61.         }
  62.     } else {
  63.         if (@dl("xml.so")) {
  64.             define("CANUSEXMLRPC", 1);
  65.         } else {
  66.             define("CANUSEXMLRPC", 0);
  67.         }
  68.     }
  69. } else {
  70.     define("CANUSEXMLRPC", 1);
  71. }
  72.  
  73. if (CANUSEXMLRPC == 1) {
  74.  
  75. $xmlrpcI4="i4";
  76. $xmlrpcInt="int";
  77. $xmlrpcBoolean="boolean";
  78. $xmlrpcDouble="double";
  79. $xmlrpcString="string";
  80. $xmlrpcDateTime="dateTime.iso8601";
  81. $xmlrpcBase64="base64";
  82. $xmlrpcArray="array";
  83. $xmlrpcStruct="struct";
  84.  
  85.  
  86. $xmlrpcTypes=array($xmlrpcI4 => 1,
  87.                    $xmlrpcInt => 1,
  88.                    $xmlrpcBoolean => 1,
  89.                    $xmlrpcString => 1,
  90.                    $xmlrpcDouble => 1,
  91.                    $xmlrpcDateTime => 1,
  92.                    $xmlrpcBase64 => 1,
  93.                    $xmlrpcArray => 2,
  94.                    $xmlrpcStruct => 3);
  95.  
  96. $xmlEntities=array(     "amp" => "&",
  97.                                      "quot" => '"',
  98.                                      "lt" => "<",
  99.                                      "gt" => ">",
  100.                                      "apos" => "'");
  101.  
  102. $xmlrpcerr["unknown_method"]=1;
  103. $xmlrpcstr["unknown_method"]="Unknown method";
  104. $xmlrpcerr["invalid_return"]=2;
  105. $xmlrpcstr["invalid_return"]="Invalid return payload: enabling debugging to examine incoming payload";
  106. $xmlrpcerr["incorrect_params"]=3;
  107. $xmlrpcstr["incorrect_params"]="Incorrect parameters passed to method";
  108. $xmlrpcerr["introspect_unknown"]=4;
  109. $xmlrpcstr["introspect_unknown"]="Can't introspect: method unknown";
  110. $xmlrpcerr["http_error"]=5;
  111. $xmlrpcstr["http_error"]="Didn't receive 200 OK from remote server.";
  112. $xmlrpcerr["no_data"]=6;
  113. $xmlrpcstr["no_data"]="No data received from server.";
  114. $xmlrpcerr["no_ssl"]=7;
  115. $xmlrpcstr["no_ssl"]="No SSL support compiled in.";
  116. $xmlrpcerr["curl_fail"]=8;
  117. $xmlrpcstr["curl_fail"]="CURL error";
  118.  
  119. $xmlrpc_defencoding="UTF-8";
  120.  
  121. $xmlrpcName="XML-RPC for PHP";
  122. $xmlrpcVersion="1.02";
  123.  
  124. // let user errors start at 800
  125. $xmlrpcerruser=800; 
  126. // let XML parse errors start at 100
  127. $xmlrpcerrxml=100;
  128.  
  129. // formulate backslashes for escaping regexp
  130. $xmlrpc_backslash=chr(92).chr(92);
  131.  
  132. // used to store state during parsing
  133. // quick explanation of components:
  134. //   st - used to build up a string for evaluation
  135. //   ac - used to accumulate values
  136. //   qt - used to decide if quotes are needed for evaluation
  137. //   cm - used to denote struct or array (comma needed)
  138. //   isf - used to indicate a fault
  139. //   lv - used to indicate "looking for a value": implements
  140. //        the logic to allow values with no types to be strings
  141. //   params - used to store parameters in method calls
  142. //   method - used to store method name
  143.  
  144. $_xh=array();
  145.  
  146. function xmlrpc_entity_decode($string) {
  147.   $top=split("&", $string);
  148.   $op="";
  149.   $i=0; 
  150.   while($i<sizeof($top)) {
  151.     if (ereg("^([#a-zA-Z0-9]+);", $top[$i], $regs)) {
  152.       $op.=ereg_replace("^[#a-zA-Z0-9]+;",
  153.                         xmlrpc_lookup_entity($regs[1]),
  154.                                             $top[$i]);
  155.     } else {
  156.       if ($i==0) 
  157.         $op=$top[$i]; 
  158.       else
  159.         $op.="&" . $top[$i];
  160.     }
  161.     $i++;
  162.   }
  163.   return $op;
  164. }
  165.  
  166. function xmlrpc_lookup_entity($ent) {
  167.   global $xmlEntities;
  168.   
  169.   if (isset($xmlEntities[strtolower($ent)]))
  170.     return $xmlEntities[strtolower($ent)];
  171.   if (ereg("^#([0-9]+)$", $ent, $regs))
  172.     return chr($regs[1]);
  173.   return "?";
  174. }
  175.  
  176. function xmlrpc_se($parser, $name, $attrs) {
  177.     global $_xh, $xmlrpcDateTime, $xmlrpcString;
  178.     
  179.     switch($name) {
  180.     case "STRUCT":
  181.     case "ARRAY":
  182.       $_xh[$parser]['st'].="array(";
  183.       $_xh[$parser]['cm']++;
  184.         // this last line turns quoting off
  185.         // this means if we get an empty array we'll 
  186.         // simply get a bit of whitespace in the eval
  187.         $_xh[$parser]['qt']=0;
  188.       break;
  189.     case "NAME":
  190.       $_xh[$parser]['st'].="'"; $_xh[$parser]['ac']="";
  191.       break;
  192.     case "FAULT":
  193.       $_xh[$parser]['isf']=1;
  194.       break;
  195.     case "PARAM":
  196.       $_xh[$parser]['st']="";
  197.       break;
  198.     case "VALUE":
  199.       $_xh[$parser]['st'].="new xmlrpcval("; 
  200.         $_xh[$parser]['vt']=$xmlrpcString;
  201.         $_xh[$parser]['ac']="";
  202.         $_xh[$parser]['qt']=0;
  203.       $_xh[$parser]['lv']=1;
  204.       // look for a value: if this is still 1 by the
  205.       // time we reach the first data segment then the type is string
  206.       // by implication and we need to add in a quote
  207.         break;
  208.  
  209.     case "I4":
  210.     case "INT":
  211.     case "STRING":
  212.     case "BOOLEAN":
  213.     case "DOUBLE":
  214.     case "DATETIME.ISO8601":
  215.     case "BASE64":
  216.       $_xh[$parser]['ac']=""; // reset the accumulator
  217.  
  218.       if ($name=="DATETIME.ISO8601" || $name=="STRING") {
  219.             $_xh[$parser]['qt']=1; 
  220.             if ($name=="DATETIME.ISO8601")
  221.                 $_xh[$parser]['vt']=$xmlrpcDateTime;
  222.       } else if ($name=="BASE64") {
  223.             $_xh[$parser]['qt']=2;
  224.         } else {
  225.             // No quoting is required here -- but
  226.             // at the end of the element we must check
  227.             // for data format errors.
  228.             $_xh[$parser]['qt']=0;
  229.       }
  230.         break;
  231.     case "MEMBER":
  232.         $_xh[$parser]['ac']="";
  233.       break;
  234.     default:
  235.         break;
  236.     }
  237.  
  238.     if ($name!="VALUE") $_xh[$parser]['lv']=0;
  239. }
  240.  
  241. function xmlrpc_ee($parser, $name) {
  242.     global $_xh,$xmlrpcTypes,$xmlrpcString;
  243.  
  244.     switch($name) {
  245.     case "STRUCT":
  246.     case "ARRAY":
  247.       if ($_xh[$parser]['cm'] && substr($_xh[$parser]['st'], -1) ==',') {
  248.         $_xh[$parser]['st']=substr($_xh[$parser]['st'],0,-1);
  249.       }
  250.       $_xh[$parser]['st'].=")";    
  251.       $_xh[$parser]['vt']=strtolower($name);
  252.       $_xh[$parser]['cm']--;
  253.       break;
  254.     case "NAME":
  255.       $_xh[$parser]['st'].= $_xh[$parser]['ac'] . "' => ";
  256.       break;
  257.     case "BOOLEAN":
  258.         // special case here: we translate boolean 1 or 0 into PHP
  259.         // constants true or false
  260.         if ($_xh[$parser]['ac']=='1') 
  261.             $_xh[$parser]['ac']="true";
  262.         else 
  263.             $_xh[$parser]['ac']="false";
  264.         $_xh[$parser]['vt']=strtolower($name);
  265.         // Drop through intentionally.
  266.     case "I4":
  267.     case "INT":
  268.     case "STRING":
  269.     case "DOUBLE":
  270.     case "DATETIME.ISO8601":
  271.     case "BASE64":
  272.       if ($_xh[$parser]['qt']==1) {
  273.             // we use double quotes rather than single so backslashification works OK
  274.             $_xh[$parser]['st'].="\"". $_xh[$parser]['ac'] . "\""; 
  275.         } else if ($_xh[$parser]['qt']==2) {
  276.             $_xh[$parser]['st'].="base64_decode('". $_xh[$parser]['ac'] . "')"; 
  277.         } else if ($name=="BOOLEAN") {
  278.             $_xh[$parser]['st'].=$_xh[$parser]['ac'];
  279.         } else {
  280.             // we have an I4, INT or a DOUBLE
  281.             // we must check that only 0123456789-.<space> are characters here
  282.             if (!ereg("^\-?[0123456789 \t\.]+$", $_xh[$parser]['ac'])) {
  283.                 // TODO: find a better way of throwing an error
  284.                 // than this!
  285.                 error_log("XML-RPC: non numeric value received in INT or DOUBLE");
  286.                 $_xh[$parser]['st'].="ERROR_NON_NUMERIC_FOUND";
  287.             } else {
  288.                 // it's ok, add it on
  289.                 $_xh[$parser]['st'].=$_xh[$parser]['ac'];
  290.             }
  291.         }
  292.         $_xh[$parser]['ac']=""; $_xh[$parser]['qt']=0;
  293.         $_xh[$parser]['lv']=3; // indicate we've found a value
  294.       break;
  295.     case "VALUE":
  296.         // deal with a string value
  297.         if (strlen($_xh[$parser]['ac'])>0 &&
  298.                 $_xh[$parser]['vt']==$xmlrpcString) {
  299.             $_xh[$parser]['st'].="\"". $_xh[$parser]['ac'] . "\""; 
  300.         }
  301.         // This if() detects if no scalar was inside <VALUE></VALUE>
  302.         // and pads an empty "".
  303.         if($_xh[$parser]['st'][strlen($_xh[$parser]['st'])-1] == '(') {
  304.             $_xh[$parser]['st'].= '""';
  305.         }
  306.         $_xh[$parser]['st'].=", '" . $_xh[$parser]['vt'] . "')";
  307.         if ($_xh[$parser]['cm']) $_xh[$parser]['st'].=",";
  308.         break;
  309.     case "MEMBER":
  310.       $_xh[$parser]['ac']=""; $_xh[$parser]['qt']=0;
  311.      break;
  312.     case "DATA":
  313.       $_xh[$parser]['ac']=""; $_xh[$parser]['qt']=0;
  314.       break;
  315.     case "PARAM":
  316.       $_xh[$parser]['params'][]=$_xh[$parser]['st'];
  317.       break;
  318.     case "METHODNAME":
  319.       $_xh[$parser]['method']=ereg_replace("^[\n\r\t ]+", "", 
  320.                                                                                  $_xh[$parser]['ac']);
  321.         break;
  322.     case "BOOLEAN":
  323.         // special case here: we translate boolean 1 or 0 into PHP
  324.         // constants true or false
  325.         if ($_xh[$parser]['ac']=='1') 
  326.             $_xh[$parser]['ac']="true";
  327.         else 
  328.             $_xh[$parser]['ac']="false";
  329.         $_xh[$parser]['vt']=strtolower($name);
  330.         break;
  331.     default:
  332.         break;
  333.     }
  334.     // if it's a valid type name, set the type
  335.     if (isset($xmlrpcTypes[strtolower($name)])) {
  336.         $_xh[$parser]['vt']=strtolower($name);
  337.     }
  338.     
  339. }
  340.  
  341. function xmlrpc_cd($parser, $data)
  342. {    
  343.   global $_xh, $xmlrpc_backslash;
  344.  
  345.   //if (ereg("^[\n\r \t]+$", $data)) return;
  346.   // print "adding [${data}]\n";
  347.  
  348.     if ($_xh[$parser]['lv']!=3) {
  349.         // "lookforvalue==3" means that we've found an entire value
  350.         // and should discard any further character data
  351.         if ($_xh[$parser]['lv']==1) {  
  352.             // if we've found text and we're just in a <value> then
  353.             // turn quoting on, as this will be a string
  354.             $_xh[$parser]['qt']=1; 
  355.             // and say we've found a value
  356.             $_xh[$parser]['lv']=2; 
  357.         }
  358.     // replace characters that eval would
  359.     // do special things with
  360.     $_xh[$parser]['ac'].=str_replace('$', '\$',
  361.         str_replace('"', '\"', str_replace(chr(92),
  362.             $xmlrpc_backslash, $data)));
  363.     }
  364. }
  365.  
  366. function xmlrpc_dh($parser, $data)
  367. {
  368.   global $_xh;
  369.   if (substr($data, 0, 1) == "&" && substr($data, -1, 1) == ";") {
  370.         if ($_xh[$parser]['lv']==1) {  
  371.             $_xh[$parser]['qt']=1; 
  372.             $_xh[$parser]['lv']=2; 
  373.         }
  374.         $_xh[$parser]['ac'].=str_replace('$', '\$',
  375.                 str_replace('"', '\"', str_replace(chr(92),
  376.                     $xmlrpc_backslash, $data)));
  377.   }
  378. }
  379.  
  380. class xmlrpc_client {
  381.   var $path;
  382.   var $server;
  383.   var $port;
  384.   var $errno;
  385.   var $errstring;
  386.   var $debug=0;
  387.   var $username="";
  388.   var $password="";
  389.   var $cert="";
  390.   var $certpass="";
  391.   
  392.   function xmlrpc_client($path, $server, $port=0) {
  393.     $this->port=$port; $this->server=$server; $this->path=$path;
  394.   }
  395.  
  396.   function setDebug($in) {
  397.         if ($in) { 
  398.             $this->debug=1;
  399.         } else {
  400.             $this->debug=0;
  401.         }
  402.   }
  403.  
  404.   function setCredentials($u, $p) {
  405.     $this->username=$u;
  406.     $this->password=$p;
  407.   }
  408.  
  409.   function setCertificate($cert, $certpass) {
  410.     $this->cert = $cert;
  411.     $this->certpass = $certpass;
  412.   }
  413.  
  414.   function send($msg, $timeout=0, $method='http') {
  415.     // where msg is an xmlrpcmsg
  416.     $msg->debug=$this->debug;
  417.  
  418.     if ($method == 'https') {
  419.       return $this->sendPayloadHTTPS($msg,
  420.                      $this->server,
  421.                      $this->port, $timeout,
  422.                      $this->username, $this->password,
  423.                      $this->cert,
  424.                      $this->certpass);
  425.     } else {
  426.       return $this->sendPayloadHTTP10($msg, $this->server, $this->port,
  427.                       $timeout, $this->username, 
  428.                       $this->password);
  429.     }
  430.   }
  431.  
  432.   function sendPayloadHTTP10($msg, $server, $port, $timeout=0,
  433.                  $username="", $password="") {
  434.     if ($port==0) $port=80;
  435.     if($timeout>0)
  436.       $fp=@fsockopen($server, $port,
  437.             $this->errno, $this->errstr, $timeout);
  438. #      $fp=@fsockopen($server, $port,
  439. #            &$this->errno, &$this->errstr, $timeout);
  440.     else
  441.       $fp=@fsockopen($server, $port,
  442.             $this->errno, $this->errstr);
  443. #      $fp=@fsockopen($server, $port,
  444. #            &$this->errno, &$this->errstr);
  445.     if (!$fp) {   
  446.       return 0;
  447.     }
  448.     // Only create the payload if it was not created previously
  449.     if(empty($msg->payload)) $msg->createPayload();
  450.     
  451.     // thanks to Grant Rauscher <grant7@firstworld.net>
  452.     // for this
  453.     $credentials="";
  454.     if ($username!="") {
  455.       $credentials="Authorization: Basic " .
  456.     base64_encode($username . ":" . $password) . "\r\n";
  457.     }
  458.     
  459.     $op= "POST " . $this->path. " HTTP/1.0\r\nUser-Agent: PHP XMLRPC 1.0\r\n" .
  460.       "Host: ". $this->server  . "\r\n" .
  461.       $credentials . 
  462.       "Content-Type: text/xml\r\nContent-Length: " .
  463.       strlen($msg->payload) . "\r\n\r\n" .
  464.       $msg->payload;
  465.     
  466.     if (!fputs($fp, $op, strlen($op))) {
  467.       $this->errstr="Write error";
  468.       return 0;
  469.     }
  470.     $resp=$msg->parseResponseFile($fp);
  471.     fclose($fp);
  472.     return $resp;
  473.   }
  474.  
  475.   // contributed by Justin Miller <justin@voxel.net>
  476.   // requires curl to be built into PHP
  477.   function sendPayloadHTTPS($msg, $server, $port, $timeout=0,
  478.                 $username="", $password="", $cert="",
  479.                 $certpass="") {
  480.     global $xmlrpcerr, $xmlrpcstr;
  481.     if ($port == 0) $port = 443;
  482.     
  483.     // Only create the payload if it was not created previously
  484.     if(empty($msg->payload)) $msg->createPayload();
  485.     
  486.     if (!function_exists("curl_init")) {
  487.       $r=new xmlrpcresp(0, $xmlrpcerr["no_ssl"],
  488.             $xmlrpcstr["no_ssl"]);
  489.       return $r;
  490.     }
  491.  
  492.     $curl = curl_init("https://" . $server . ':' . $port .
  493.               $this->path);
  494.     
  495.     curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
  496.     // results into variable
  497.     if ($this->debug) {
  498.       curl_setopt($curl, CURLOPT_VERBOSE, 1);
  499.     }
  500.     curl_setopt($curl, CURLOPT_USERAGENT, 'PHP XMLRPC 1.0');
  501.     // required for XMLRPC
  502.     curl_setopt($curl, CURLOPT_POST, 1);
  503.     // post the data
  504.     curl_setopt($curl, CURLOPT_POSTFIELDS, $msg->payload);
  505.     // the data
  506.     curl_setopt($curl, CURLOPT_HEADER, 1);
  507.     // return the header too
  508.     curl_setopt($curl, CURLOPT_HTTPHEADER, array('Content-Type: text/xml'));
  509.     // required for XMLRPC
  510.     if ($timeout) curl_setopt($curl, CURLOPT_TIMEOUT, $timeout == 1 ? 1 :
  511.                   $timeout - 1);
  512.     // timeout is borked
  513.     if ($username && $password) curl_setopt($curl, CURLOPT_USERPWD,
  514.                         "$username:$password"); 
  515.     // set auth stuff
  516.     if ($cert) curl_setopt($curl, CURLOPT_SSLCERT, $cert);
  517.     // set cert file
  518.     if ($certpass) curl_setopt($curl, CURLOPT_SSLCERTPASSWD,
  519.                    $certpass);                    
  520.     // set cert password
  521.     
  522.     $result = curl_exec($curl);
  523.     
  524.     if (!$result) {
  525.       $resp=new xmlrpcresp(0, 
  526.                $xmlrpcerr["curl_fail"],
  527.                $xmlrpcstr["curl_fail"]. ": ". 
  528.                curl_error($curl));
  529.     } else {
  530.       $resp = $msg->parseResponse($result);
  531.     }
  532.     curl_close($curl);
  533.     return $resp;
  534.   }
  535.  
  536. } // end class xmlrpc_client
  537.  
  538. class xmlrpcresp {
  539.   var $xv;
  540.   var $fn;
  541.   var $fs;
  542.   var $hdrs;
  543.  
  544.   function xmlrpcresp($val, $fcode=0, $fstr="") {
  545.     if ($fcode!=0) {
  546.       $this->xv=0;
  547.       $this->fn=$fcode;
  548.       $this->fs=trim(htmlspecialchars($fstr));
  549.       logIO("O",$this->fs);
  550.     } else {
  551.       $this->xv=$val;
  552.       $this->fn=0;
  553.     }
  554.   }
  555.  
  556.   function faultCode() { 
  557.         if (isset($this->fn)) 
  558.             return $this->fn;
  559.         else
  560.             return 0; 
  561.     }
  562.  
  563.   function faultString() { return $this->fs; }
  564.   function value() { return $this->xv; }
  565.  
  566.   function serialize() { 
  567.     $rs="<methodResponse>";
  568.     if ($this->fn) {
  569.       $rs.="<fault>
  570.   <value>
  571.     <struct>
  572.       <member>
  573.         <name>faultCode</name>
  574.         <value><int>" . $this->fn . "</int></value>
  575.       </member>
  576.       <member>
  577.         <name>faultString</name>
  578.         <value><string>" . $this->fs . "</string></value>
  579.       </member>
  580.     </struct>
  581.   </value>
  582. </fault>";
  583.     } else {
  584.       $rs.="<params><param>" . $this->xv->serialize() . 
  585.         "</param></params>";
  586.     }
  587.     $rs.="</methodResponse>";
  588.  
  589.     /* begin Logging
  590.     $f=fopen("xmlrpc/xmlrpc.log","a+");
  591.     fwrite($f, date("Ymd H:i:s")."\n\nResponse:\n\n".$rs);
  592.     fclose($f);
  593.     end Logging */
  594.     logIO("O",$rs);
  595.  
  596.     return $rs;
  597.   }
  598. }
  599.  
  600. class xmlrpcmsg {
  601.   var $payload;
  602.   var $methodname;
  603.   var $params=array();
  604.   var $debug=0;
  605.  
  606.   function xmlrpcmsg($meth, $pars=0) {
  607.         $this->methodname=$meth;
  608.         if (is_array($pars) && sizeof($pars)>0) {
  609.             for($i=0; $i<sizeof($pars); $i++) 
  610.                 $this->addParam($pars[$i]);
  611.         }
  612.   }
  613.  
  614.   function xml_header() {
  615.     /* commenting this out until we get further testing...
  616.     if (function_exists('get_settings')) {
  617.         $encoding = ' encoding="'.get_settings('blog_charset').'"';
  618.     } else {
  619.         $encoding = '';
  620.     }
  621.     */
  622.     $encoding = '';
  623.     return "<?xml version=\"1.0\"$encoding?".">\n<methodCall>\n";
  624.   }
  625.  
  626.   function xml_footer() {
  627.     return "</methodCall>\n";
  628.   }
  629.  
  630.   function createPayload() {
  631.     $this->payload=$this->xml_header();
  632.     $this->payload.="<methodName>" . $this->methodname . "</methodName>\n";
  633.     //    if (sizeof($this->params)) {
  634.       $this->payload.="<params>\n";
  635.       for($i=0; $i<sizeof($this->params); $i++) {
  636.         $p=$this->params[$i];
  637.         $this->payload.="<param>\n" . $p->serialize() .
  638.           "</param>\n";
  639.       }
  640.       $this->payload.="</params>\n";
  641.     // }
  642.     $this->payload.=$this->xml_footer();
  643.     $this->payload=str_replace("\n", "\r\n", $this->payload);
  644.   }
  645.  
  646.   function method($meth="") {
  647.     if ($meth!="") {
  648.       $this->methodname=$meth;
  649.     }
  650.     return $this->methodname;
  651.   }
  652.  
  653.   function serialize() {
  654.         $this->createPayload();
  655.         logIO("O",$this->payload);
  656.         return $this->payload;
  657.   }
  658.  
  659.   function addParam($par) { $this->params[]=$par; }
  660.   function getParam($i) { return $this->params[$i]; }
  661.   function getNumParams() { return sizeof($this->params); }
  662.  
  663.   function parseResponseFile($fp) {
  664.     $ipd="";
  665.  
  666.     while($data=fread($fp, 32768)) {
  667.       $ipd.=$data;
  668.     }
  669.     return $this->parseResponse($ipd);
  670.   }
  671.  
  672.   function parseResponse($data="") {
  673.     global $_xh,$xmlrpcerr,$xmlrpcstr;
  674.     global $xmlrpc_defencoding;
  675.  
  676.     
  677.     $parser = xml_parser_create($xmlrpc_defencoding);
  678.  
  679.     $_xh[$parser]=array();
  680.  
  681.     $_xh[$parser]['st']=""; 
  682.     $_xh[$parser]['cm']=0; 
  683.     $_xh[$parser]['isf']=0; 
  684.     $_xh[$parser]['ac']="";
  685.     $_xh[$parser]['qt']="";
  686.     $_xh[$parser]['ha']="";
  687.     $_xh[$parser]['ac']="";
  688.  
  689.     xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, true);
  690.     xml_set_element_handler($parser, "xmlrpc_se", "xmlrpc_ee");
  691.     xml_set_character_data_handler($parser, "xmlrpc_cd");
  692.     xml_set_default_handler($parser, "xmlrpc_dh");
  693.     $xmlrpc_value=new xmlrpcval;
  694.  
  695.     if ($this->debug)
  696.       print "<PRE>---GOT---\n" . htmlspecialchars($data) . 
  697.         "\n---END---\n</PRE>";
  698.     if ($data=="") {
  699.       error_log("No response received from server.");
  700.       $r=new xmlrpcresp(0, $xmlrpcerr["no_data"],
  701.                 $xmlrpcstr["no_data"]);
  702.       xml_parser_free($parser);
  703.       return $r;
  704.     }
  705.     // see if we got an HTTP 200 OK, else bomb
  706.     // but only do this if we're using the HTTP protocol.
  707.     if (ereg("^HTTP",$data) && 
  708.             !ereg("^HTTP/[0-9\.]+ 200 ", $data)) {
  709.         $errstr= substr($data, 0, strpos($data, "\n")-1);
  710.         error_log("HTTP error, got response: " .$errstr);
  711.         $r=new xmlrpcresp(0, $xmlrpcerr["http_error"],
  712.                   $xmlrpcstr["http_error"]. " (" . $errstr . ")");
  713.         xml_parser_free($parser);
  714.         return $r;
  715.     }
  716.  
  717.     // if using HTTP, then gotta get rid of HTTP headers here
  718.     // and we store them in the 'ha' bit of our data array
  719.     if (ereg("^HTTP", $data)) {
  720.         $ar=explode("\r\n", $data);
  721.         $newdata="";
  722.         $hdrfnd=0;
  723.         for ($i=0; $i<sizeof($ar); $i++) {
  724.             if (!$hdrfnd) {
  725.                 if (strlen($ar[$i])>0) {
  726.                     $_xh[$parser]['ha'].=$ar[$i]. "\r\n";
  727.                 } else {
  728.                     $hdrfnd=1; 
  729.                 }
  730.             } else {
  731.                 $newdata.=$ar[$i] . "\r\n";
  732.             }
  733.         }
  734.         $data=$newdata;
  735.     }
  736.     
  737.     if (!xml_parse($parser, $data, sizeof($data))) {
  738.         // thanks to Peter Kocks <peter.kocks@baygate.com>
  739.         if((xml_get_current_line_number($parser)) == 1)   
  740.             $errstr = "XML error at line 1, check URL";
  741.         else
  742.             $errstr = sprintf("XML error: %s at line %d",
  743.                                                 xml_error_string(xml_get_error_code($parser)),
  744.                                                 xml_get_current_line_number($parser));
  745.         error_log($errstr);
  746.         $r=new xmlrpcresp(0, $xmlrpcerr["invalid_return"],
  747.                                             $xmlrpcstr["invalid_return"]);
  748.         xml_parser_free($parser);
  749.         return $r;
  750.     }
  751.     xml_parser_free($parser);
  752.     if ($this->debug) {
  753.       print "<PRE>---EVALING---[" . 
  754.         strlen($_xh[$parser]['st']) . " chars]---\n" . 
  755.         htmlspecialchars($_xh[$parser]['st']) . ";\n---END---</PRE>";
  756.     }
  757.     if (strlen($_xh[$parser]['st'])==0) {
  758.       // then something odd has happened
  759.       // and it's time to generate a client side error
  760.       // indicating something odd went on
  761.       $r=new xmlrpcresp(0, $xmlrpcerr["invalid_return"],
  762.                         $xmlrpcstr["invalid_return"]);
  763.     } else {
  764.       eval('$v=' . $_xh[$parser]['st'] . '; $allOK=1;');
  765.       if ($_xh[$parser]['isf']) {
  766.         $f=$v->structmem("faultCode");
  767.         $fs=$v->structmem("faultString");
  768.         $r=new xmlrpcresp($v, 
  769.             $f->scalarval(), 
  770.             $fs->scalarval());
  771.       } else {
  772.         $r=new xmlrpcresp($v);
  773.       }
  774.     }
  775.     $r->hdrs=split("\r?\n", $_xh[$parser]['ha']);
  776.     return $r;
  777.   }
  778.  
  779. }
  780.  
  781. class xmlrpcval {
  782.   var $me=array();
  783.   var $mytype=0;
  784.  
  785.   function xmlrpcval($val=-1, $type="") {
  786.           global $xmlrpcTypes;
  787.         // but this doesn't work, so we redefine it. WEIRD BUG ALERT
  788.         $xmlrpcI4="i4";
  789.         $xmlrpcInt="int";
  790.         $xmlrpcBoolean="boolean";
  791.         $xmlrpcDouble="double";
  792.         $xmlrpcString="string";
  793.         $xmlrpcDateTime="dateTime.iso8601";
  794.         $xmlrpcBase64="base64";
  795.         $xmlrpcArray="array";
  796.         $xmlrpcStruct="struct";
  797.         $xmlrpcTypes=array($xmlrpcI4 => 1,
  798.                    $xmlrpcInt => 1,
  799.                    $xmlrpcBoolean => 1,
  800.                    $xmlrpcString => 1,
  801.                    $xmlrpcDouble => 1,
  802.                    $xmlrpcDateTime => 1,
  803.                    $xmlrpcBase64 => 1,
  804.                    $xmlrpcArray => 2,
  805.                     $xmlrpcStruct => 3);
  806.         //   print_r($xmlrpcTypes);
  807.         $this->me=array();
  808.         $this->mytype=0;
  809.         if ($val!=-1 || $type!="") {
  810.             if ($type=="") $type="string";
  811.             if ($xmlrpcTypes[$type]==1) {
  812.                 $this->addScalar($val,$type);
  813.             }
  814.       else if ($xmlrpcTypes[$type]==2)
  815.             $this->addArray($val);
  816.             else if ($xmlrpcTypes[$type]==3)
  817.                 $this->addStruct($val);
  818.         }
  819.   }
  820.  
  821.   function addScalar($val, $type="string") {
  822.         global $xmlrpcTypes, $xmlrpcBoolean;
  823.  
  824.         if ($this->mytype==1) {
  825.             echo "<B>xmlrpcval</B>: scalar can have only one value<BR>";
  826.             return 0;
  827.         }
  828.         $typeof=$xmlrpcTypes[$type];
  829.         if ($typeof!=1) {
  830.             echo "<B>xmlrpcval</B>: not a scalar type (${typeof})<BR>";
  831.             return 0;
  832.         }
  833.         
  834.         if ($type==$xmlrpcBoolean) {
  835.             if (strcasecmp($val,"true")==0 || 
  836.                     $val==1 || ($val==true &&
  837.                                             strcasecmp($val,"false"))) {
  838.                 $val=1;
  839.             } else {
  840.                 $val=0;
  841.             }
  842.         }
  843.         
  844.         if ($this->mytype==2) {
  845.             // we're adding to an array here
  846.             $ar=$this->me["array"];
  847.             $ar[]=new xmlrpcval($val, $type);
  848.             $this->me["array"]=$ar;
  849.         } else {
  850.             // a scalar, so set the value and remember we're scalar
  851.             $this->me[$type]=$val;
  852.             $this->mytype=$typeof;
  853.         }
  854.         return 1;
  855.   }
  856.  
  857.   function addArray($vals) {
  858.         global $xmlrpcTypes;
  859.         if ($this->mytype!=0) {
  860.             echo "<B>xmlrpcval</B>: already initialized as a [" . 
  861.                 $this->kindOf() . "]<BR>";
  862.             return 0;
  863.         }
  864.  
  865.         $this->mytype=$xmlrpcTypes["array"];
  866.         $this->me["array"]=$vals;
  867.         return 1;
  868.   }
  869.  
  870.   function addStruct($vals) {
  871.     global $xmlrpcTypes;
  872.     if ($this->mytype!=0) {
  873.       echo "<B>xmlrpcval</B>: already initialized as a [" . 
  874.         $this->kindOf() . "]<BR>";
  875.       return 0;
  876.     }
  877.     $this->mytype=$xmlrpcTypes["struct"];
  878.     $this->me["struct"]=$vals;
  879.     return 1;
  880.   }
  881.  
  882.   function dump($ar) {
  883.     reset($ar);
  884.     while ( list( $key, $val ) = each( $ar ) ) {
  885.       echo "$key => $val<br>";
  886.       if ($key == 'array')
  887.         while ( list( $key2, $val2 ) = each( $val ) ) {
  888.           echo "-- $key2 => $val2<br>";
  889.         }
  890.     }
  891.   }
  892.  
  893.   function kindOf() {
  894.     switch($this->mytype) {
  895.     case 3:
  896.       return "struct";
  897.       break;
  898.     case 2:
  899.       return "array";
  900.       break;
  901.     case 1:
  902.       return "scalar";
  903.       break;
  904.     default:
  905.       return "undef";
  906.     }
  907.   }
  908.  
  909.   function serializedata($typ, $val) {
  910.         $rs="";
  911.         global $xmlrpcTypes, $xmlrpcBase64, $xmlrpcString,
  912.             $xmlrpcBoolean;
  913.         switch($xmlrpcTypes[$typ]) {
  914.         case 3:
  915.             // struct
  916.             $rs.="<struct>\n";
  917.             reset($val);
  918.             while(list($key2, $val2)=each($val)) {
  919.                 $rs.="<member><name>${key2}</name>\n";
  920.                 $rs.=$this->serializeval($val2);
  921.                 $rs.="</member>\n";
  922.             }
  923.             $rs.="</struct>";
  924.             break;
  925.         case 2:
  926.             // array
  927.             $rs.="<array>\n<data>\n";
  928.             for($i=0; $i<sizeof($val); $i++) {
  929.                 $rs.=$this->serializeval($val[$i]);
  930.             }
  931.             $rs.="</data>\n</array>";
  932.             break;
  933.         case 1:
  934.             switch ($typ) {
  935.             case $xmlrpcBase64:
  936.                 $rs.="<${typ}>" . base64_encode($val) . "</${typ}>";
  937.                 break;
  938.             case $xmlrpcBoolean:
  939.                 $rs.="<${typ}>" . ($val ? "1" : "0") . "</${typ}>";
  940.                     break;
  941.             case $xmlrpcString:
  942.                 $rs.="<${typ}>" . htmlspecialchars($val). "</${typ}>";
  943.                 break;
  944.             default:
  945.                 $rs.="<${typ}>${val}</${typ}>";
  946.             }
  947.             break;
  948.         default:
  949.             break;
  950.         }
  951.         return $rs;
  952.   }
  953.  
  954.   function serialize() {
  955.     return $this->serializeval($this);
  956.   }
  957.  
  958.   function serializeval($o) {
  959.         global $xmlrpcTypes;
  960.         $rs="";
  961.         $ar=$o->me;
  962.         reset($ar);
  963.         list($typ, $val) = each($ar);
  964.         $rs.="<value>";
  965.         $rs.=$this->serializedata($typ, $val);
  966.         $rs.="</value>\n";
  967.         return $rs;
  968.   }
  969.  
  970.   function structmem($m) {
  971.         $nv=$this->me["struct"][$m];
  972.         return $nv;
  973.   }
  974.  
  975.     function structreset() {
  976.         reset($this->me["struct"]);
  977.     }
  978.     
  979.     function structeach() {
  980.         return each($this->me["struct"]);
  981.     }
  982.  
  983.   function getval() {
  984.         // UNSTABLE
  985.         global $xmlrpcBoolean, $xmlrpcBase64;
  986.         reset($this->me);
  987.         list($a,$b)=each($this->me);
  988.         // contributed by I Sofer, 2001-03-24
  989.         // add support for nested arrays to scalarval
  990.         // i've created a new method here, so as to
  991.         // preserve back compatibility
  992.  
  993.         if (is_array($b))    {
  994.             foreach ($b as $id => $cont) {
  995.                 $b[$id] = $cont->scalarval();
  996.             }
  997.         }
  998.  
  999.         // add support for structures directly encoding php objects
  1000.         if (is_object($b))  {
  1001.             $t = get_object_vars($b);
  1002.             foreach ($t as $id => $cont) {
  1003.                 $t[$id] = $cont->scalarval();
  1004.             }
  1005.             foreach ($t as $id => $cont) {
  1006.                 eval('$b->'.$id.' = $cont;');
  1007.             }
  1008.         }
  1009.         // end contrib
  1010.         return $b;
  1011.   }
  1012.  
  1013.   function scalarval() {
  1014.         global $xmlrpcBoolean, $xmlrpcBase64;
  1015.         reset($this->me);
  1016.         list($a,$b)=each($this->me);
  1017.         return $b;
  1018.   }
  1019.  
  1020.   function scalartyp() {
  1021.         global $xmlrpcI4, $xmlrpcInt;
  1022.         reset($this->me);
  1023.         list($a,$b)=each($this->me);
  1024.         if ($a==$xmlrpcI4) 
  1025.             $a=$xmlrpcInt;
  1026.         return $a;
  1027.   }
  1028.  
  1029.   function arraymem($m) {
  1030.         $nv=$this->me["array"][$m];
  1031.         return $nv;
  1032.   }
  1033.  
  1034.   function arraysize() {
  1035.         reset($this->me);
  1036.         list($a,$b)=each($this->me);
  1037.         return sizeof($b);
  1038.   }
  1039. }
  1040.  
  1041. // date helpers
  1042. function iso8601_encode($timet, $utc=0) {
  1043.     // return an ISO8601 encoded string
  1044.     // really, timezones ought to be supported
  1045.     // but the XML-RPC spec says:
  1046.     //
  1047.     // "Don't assume a timezone. It should be specified by the server in its
  1048.   // documentation what assumptions it makes about timezones."
  1049.     // 
  1050.     // these routines always assume localtime unless 
  1051.     // $utc is set to 1, in which case UTC is assumed
  1052.     // and an adjustment for locale is made when encoding
  1053.     if (!$utc) {
  1054.         $t=strftime("%Y%m%dT%H:%M:%S", $timet);
  1055.     } else {
  1056.         if (function_exists("gmstrftime")) 
  1057.             // gmstrftime doesn't exist in some versions
  1058.             // of PHP
  1059.             $t=gmstrftime("%Y%m%dT%H:%M:%S", $timet);
  1060.         else {
  1061.             $t=strftime("%Y%m%dT%H:%M:%S", $timet-date("Z"));
  1062.         }
  1063.     }
  1064.     return $t;
  1065. }
  1066.  
  1067. function iso8601_decode($idate, $utc=0) {
  1068.     // return a timet in the localtime, or UTC
  1069.     $t=0;
  1070.     if (ereg("([0-9]{4})([0-9]{2})([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})",
  1071.                      $idate, $regs)) {
  1072.         if ($utc) {
  1073.             $t=gmmktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]);
  1074.         } else {
  1075.             $t=mktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]);
  1076.         }
  1077.     } 
  1078.     return $t;
  1079. }
  1080.  
  1081. /****************************************************************
  1082. * xmlrpc_decode takes a message in PHP xmlrpc object format and *
  1083. * tranlates it into native PHP types.                           *
  1084. *                                                               *
  1085. * author: Dan Libby (dan@libby.com)                             *
  1086. ****************************************************************/
  1087. if (!function_exists('phpxmlrpc_decode')) {
  1088.     function phpxmlrpc_decode($xmlrpc_val) {
  1089.        $kind = @$xmlrpc_val->kindOf();
  1090.  
  1091.        if($kind == "scalar") {
  1092.           return $xmlrpc_val->scalarval();
  1093.        }
  1094.        else if($kind == "array") {
  1095.           $size = $xmlrpc_val->arraysize();
  1096.           $arr = array();
  1097.  
  1098.           for($i = 0; $i < $size; $i++) {
  1099.              $arr[]=phpxmlrpc_decode($xmlrpc_val->arraymem($i));
  1100.           }
  1101.           return $arr; 
  1102.        }
  1103.        else if($kind == "struct") {
  1104.           $xmlrpc_val->structreset();
  1105.           $arr = array();
  1106.  
  1107.           while(list($key,$value)=$xmlrpc_val->structeach()) {
  1108.              $arr[$key] = phpxmlrpc_decode($value);
  1109.           }
  1110.           return $arr;
  1111.        }
  1112.     }
  1113. }
  1114.  
  1115. /****************************************************************
  1116. * xmlrpc_encode takes native php types and encodes them into    *
  1117. * xmlrpc PHP object format.                                     *
  1118. * BUG: All sequential arrays are turned into structs.  I don't  *
  1119. * know of a good way to determine if an array is sequential     *
  1120. * only.                                                         *
  1121. *                                                               *
  1122. * feature creep -- could support more types via optional type   *
  1123. * argument.                                                     *
  1124. *                                                               *
  1125. * author: Dan Libby (dan@libby.com)                             *
  1126. ****************************************************************/
  1127. if (!function_exists('phpxmlrpc_encode')) {
  1128.     function phpxmlrpc_encode($php_val) {
  1129.        global $xmlrpcInt;
  1130.        global $xmlrpcDouble;
  1131.        global $xmlrpcString;
  1132.        global $xmlrpcArray;
  1133.        global $xmlrpcStruct;
  1134.        global $xmlrpcBoolean;
  1135.  
  1136.        $type = gettype($php_val);
  1137.        $xmlrpc_val = new xmlrpcval;
  1138.  
  1139.        switch($type) {
  1140.           case "array":
  1141.           case "object":
  1142.              $arr = array();
  1143.              while (list($k,$v) = each($php_val)) {
  1144.                 $arr[$k] = phpxmlrpc_encode($v);
  1145.              }
  1146.              $xmlrpc_val->addStruct($arr);
  1147.              break;
  1148.           case "integer":
  1149.              $xmlrpc_val->addScalar($php_val, $xmlrpcInt);
  1150.              break;
  1151.           case "double":
  1152.              $xmlrpc_val->addScalar($php_val, $xmlrpcDouble);
  1153.              break;
  1154.           case "string":
  1155.              $xmlrpc_val->addScalar($php_val, $xmlrpcString);
  1156.              break;
  1157.     // <G_Giunta_2001-02-29>
  1158.     // Add support for encoding/decoding of booleans, since they are supported in PHP
  1159.           case "boolean":
  1160.              $xmlrpc_val->addScalar($php_val, $xmlrpcBoolean);
  1161.              break;
  1162.     // </G_Giunta_2001-02-29>
  1163.           case "unknown type":
  1164.           default:
  1165.         // giancarlo pinerolo <ping@alt.it>
  1166.         // it has to return 
  1167.             // an empty object in case (which is already
  1168.         // at this point), not a boolean. 
  1169.         break;
  1170.        }
  1171.        return $xmlrpc_val;
  1172.     }
  1173. }
  1174.  
  1175.  
  1176.  
  1177. }
  1178. ?>
  1179.